package compress

import (
	"fmt"
	"github.com/klauspost/compress/zip"
	"github.com/nwaples/rardecode/v2"
	"io"
	"os"
	"path/filepath"
)

type Compressor interface {
	Compress(output io.Writer, files []string) error
	Decompress(input io.Reader, destination string) error
}

type ZipCompressor struct{}

func (zc ZipCompressor) Compress(output io.Writer, files []string) error {
	zipWriter := zip.NewWriter(output)
	defer func(zipWriter *zip.Writer) {
		err := zipWriter.Close()
		if err != nil {
			panic(err)
		}
	}(zipWriter)

	for _, file := range files {
		f, err := os.Open(file)
		if err != nil {
			return err
		}
		defer func(f *os.File) {
			err := f.Close()
			if err != nil {
				panic(err)
			}
		}(f)

		w, err := zipWriter.Create(filepath.Base(file))
		if err != nil {
			return err
		}
		if _, err := io.Copy(w, f); err != nil {
			return err
		}
	}

	return nil
}
func (zc ZipCompressor) Decompress(input io.Reader, dest string) error {
	//zipReader, err := zip.NewReader(input, int64(input.(io.Seeker).Size()))
	//if err != nil {
	//	return err
	//}
	//
	//for _, file := range zipReader.File {
	//	f, err := file.Open()
	//	if err != nil {
	//		return err
	//	}
	//	defer f.Close()
	//
	//	destPath := filepath.Join(dest, file.Name)
	//	destFile, err := os.Create(destPath)
	//	if err != nil {
	//		return err
	//	}
	//	defer destFile.Close()
	//
	//	if _, err := io.Copy(destFile, f); err != nil {
	//		return err
	//	}
	//}
	return nil
}

//type TarGzCompressor struct{}
//
//func (r TarGzCompressor) Compress(output io.Writer, files []string) error {
//	return archiver.CompressedArchive{archiver.Tar{}, archiver.Gz{}}.Archive(files, output)
//}
//func (r TarGzCompressor) Decompress(input io.Reader, dest string) error {
//	return archiver.CompressedArchive{archiver.Tar{}, archiver.Gz{}}.Unarchive(input, dest)
//}

type RarCompressor struct{}

func (r RarCompressor) Compress(output io.Writer, files []string) error {
	return fmt.Errorf("RAR compression not implemented")
}
func (r RarCompressor) Decompress(input io.Reader, dest string) error {
	rr, err := rardecode.NewReader(input)
	if err != nil {
		return err
	}

	for {
		header, err := rr.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		destPath := filepath.Join(dest, header.Name)
		destFile, err := os.Create(destPath)
		if err != nil {
			return err
		}
		defer func(destFile *os.File) {
			err := destFile.Close()
			if err != nil {
				panic(err)
			}
		}(destFile)

		if _, err := io.Copy(destFile, rr); err != nil {
			return err
		}
	}
	return nil
}

//func CompressToZip(output io.Writer, files []string) error {
//	zipWriter := zip.NewWriter(output)
//	defer zipWriter.Close()
//
//	for _, file := range files {
//		f, err := os.Open(file)
//		if err != nil {
//			return err
//		}
//		defer f.Close()
//
//		w, err := zipWriter.Create(filepath.Base(file))
//		if err != nil {
//			return err
//		}
//		if _, err := io.Copy(w, f); err != nil {
//			return err
//		}
//	}
//	return nil
//}
//func DecompressZip(input io.Reader, dest string) error {
//	zipReader, err := zip.NewReader(input, int64(input.(io.Seeker).Size()))
//	if err != nil {
//		return err
//	}
//
//	for _, file := range zipReader.File {
//		f, err := file.Open()
//		if err != nil {
//			return err
//		}
//		defer f.Close()
//
//		destPath := filepath.Join(dest, file.Name)
//		destFile, err := os.Create(destPath)
//		if err != nil {
//			return err
//		}
//		defer destFile.Close()
//
//		if _, err := io.Copy(destFile, f); err != nil {
//			return err
//		}
//	}
//	return nil
//}
//func CompressWithArchiver(outputFile string, files []string, format archiver.Format) error {
//	return format.Archive(files, outputFile)
//}
//func DecompressWithArchiver(inputFile, dest string, format archiver.Format) error {
//	return format.Unarchive(inputFile, dest)
//}
//func DecompressRar(input io.Reader, dest string) error {
//	rr, err := rardecode.NewReader(input, "")
//	if err != nil {
//		return err
//	}
//
//	for {
//		header, err := rr.Next()
//		if err == io.EOF {
//			break
//		}
//		if err != nil {
//			return err
//		}
//
//		destPath := filepath.Join(dest, header.Name)
//		destFile, err := os.Create(destPath)
//		if err != nil {
//			return err
//		}
//		defer destFile.Close()
//
//		if _, err := io.Copy(destFile, rr); err != nil {
//			return err
//		}
//	}
//	return nil
//}
